﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Text.RegularExpressions;
using WebChatApi.Common.Interface;
using System.Web;

namespace WebChatApi.Common
{
    /// <summary>
    /// 
    /// </summary>
    [DataContract]
    [KnownType(typeof(Uri))]
    public class TrackableLink
    {
        /// <summary>
        /// The base URL
        /// </summary>
        protected const string baseUrl = "http://jibo.cn/go/";

        /// <summary>
        /// The parameter format
        /// </summary>
        protected const string parameterFormat = "d={0}&u={1}&t={2}&ts={3}&e={4}";

        /// <summary>
        /// The parameter regex
        /// </summary>
        protected static Regex parameterRegex = new Regex(@"d=(?<Destination>(http(s)?%3a%2f%2f[\w%-.]+))&u=(?<UserKey>([\w-]*))&t=(?<TemplateKey>([\w-]*))&ts=(?<TemplateStamp>([\w%-.]*))&e=(?<Email>([\w%-@.]*))", RegexOptions.Compiled);

        /// <summary>
        /// The navigation point
        /// </summary>
        protected readonly string navigationPoint;

        #region Properties

        /// <summary>
        /// Gets or sets the navigate URL.
        /// </summary>
        /// <value>
        /// The navigate URL.
        /// </value>
        [DataMember]
        public string NavigateUrl
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the original navigate URL.
        /// </summary>
        /// <value>
        /// The original navigate URL.
        /// </value>
        public string OriginalNavigateUrl
        {
            get
            {
                return HttpUtility.UrlDecode(this.NavigateUrl);
            }
        }

        /// <summary>
        /// Gets or sets the template key.
        /// </summary>
        /// <value>
        /// The template key.
        /// </value>
        [DataMember]
        public Guid? TemplateKey
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the user key.
        /// </summary>
        /// <value>
        /// The user key.
        /// </value>
        [DataMember]
        public Guid? UserKey
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the email.
        /// </summary>
        /// <value>
        /// The email.
        /// </value>
        [DataMember]
        public string Email
        { get; set; }

        /// <summary>
        /// Gets or sets the template stamp.
        /// (version, time, etc.)
        /// </summary>
        /// <value>
        /// The template stamp.
        /// </value>
        [DataMember]
        public string TemplateStamp
        {
            get;
            set;
        }

        #endregion

        #region Contructor

        /// <summary>
        /// Initializes a new instance of the <see cref="TrackableLink" /> class.
        /// </summary>
        public TrackableLink()
            : this(null)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TrackableLink" /> class.
        /// </summary>
        /// <param name="navigateUrl">The navigate URL.</param>
        public TrackableLink(string navigateUrl)
        {
            this.NavigateUrl = navigateUrl;

            //// The navigation point.
            //// t: Template key
            //// d: Destination string
            //// u: User key
            //// ts: Template stamp (version, time, etc.)
            navigationPoint = parameterFormat;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TrackableLink"/> class.
        /// </summary>
        /// <param name="navigateUrl">The navigate URL.</param>
        /// <param name="userKey">The user key.</param>
        /// <param name="templateKey">The template key.</param>
        /// <param name="templateStamp">The template stamp.</param>
        public TrackableLink(string navigateUrl, Guid userKey, Guid templateKey, string templateStamp)
            : this(navigateUrl)
        {
            this.UserKey = userKey;
            this.TemplateKey = templateKey;
            this.TemplateStamp = templateStamp;
        }

        #endregion

        /// <summary>
        /// Returns a <see cref="System.String" /> that represents this instance.
        /// </summary>
        /// <returns>
        /// A <see cref="System.String" /> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return this.NavigateUrl == null ? string.Empty : string.Format(
                this.navigationPoint,
                //d: Destination string
                this.NavigateUrl.ToString().ToUrlPathEncodedText(),
                //u: User key
                this.UserKey.GetStringValue(),
                //t: Template key
                this.TemplateKey.GetStringValue(),
                // ts: Template stamp (version, time, etc.)
                string.IsNullOrWhiteSpace(this.TemplateStamp) ? string.Empty : this.TemplateStamp,
                string.IsNullOrWhiteSpace(this.Email) ? string.Empty : this.Email);
        }

        /// <summary>
        /// Translates the trackable link.
        /// </summary>
        /// <param name="url">The URL.</param>
        /// <returns></returns>
        public static TrackableLink TranslateTrackableLink(string url)
        {
            TrackableLink result = null;
            if (url != null)
            {
                Match match = parameterRegex.Match(url.ToString());
                if (match != null && match.Success)
                {
                    string destination = match.Result("${Destination}");
                    string userKeyString = match.Result("${UserKey}");
                    string templateKeyString = match.Result("${TemplateKey}");
                    string templateStamp = match.Result("${TemplateStamp}");
                    string userEmail = match.Result("${Email}");
                    string uri = string.Empty;

                    if (!string.IsNullOrWhiteSpace(destination))
                    {
                        uri = destination;
                    }

                    Guid userKey;
                    Guid templateKey;

                    result = new TrackableLink
                    {
                        NavigateUrl = uri,
                        UserKey = Guid.TryParse(userKeyString, out userKey) ? (userKey as Guid?) : null,
                        TemplateKey = Guid.TryParse(templateKeyString, out templateKey) ? templateKey as Guid? : null,
                        TemplateStamp = templateStamp,
                        Email = userEmail
                    };
                }
            }

            return result;
        }
    }
}
